
#include <QtXml/qdom.h>

#include "InstantReplayThread.h"


#include "PsoSharingMethods.h"
#include "ui/ui_Inspector.h"

#include "MainWindow.h"
#include "QGLRenderer.h"

#include "FreeSimulationThread.h"
#include "EvolutiveSimulationThread.h"
#include "EvolutionOfBehavior.h"

#include "HalfHumanCreature.h"
#include "HumanCreature.h"
#include "BasicCreature.h"
#include "QuadrupedCreature.h"
#include "PrimitiveCreature.h"
#include "MatchCreature.h"

#include "PsoVelocityClampingMethods.h"
#include "EvolutionOfMorphologyAndBehavior.h"
#include "ExperimentDirectorThread.h"

#include <QtCore/QString>
#include <QtGui/QClipboard>

namespace jcrada {

    MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent),
    _inspector(new Inspector()),
    _ui_main_window(new Ui::MainWindow()),
    _ui_inspector(new Ui::Inspector()),
    _simulation_thread(NULL),
    _renderer_thread(new QGLRendererThread()),
    _creature(NULL),
    _evolution_of_creatures(NULL),
    _toggle_color_message(false),
    _activate_shortcuts(false),
    _body_part_selection_index(0),
    _hook(NULL),
    _experiment_threads(new std::vector<ExperimentThread*>()) {

    }

    MainWindow::~MainWindow() {
        delete _renderer_thread;
        delete _simulation_thread;

        delete _ui_inspector;
        delete _ui_main_window;

        delete _inspector;
        if (_creature) {
            delete _creature;
        }
        if (_evolution_of_creatures) {
            delete _evolution_of_creatures;
        }
        for (int i = 0; i < _experiment_threads->size(); ++i) {
            delete _experiment_threads->at(i);
        }
        delete _experiment_threads;
    }

    void MainWindow::updateControls() {
        getUiInspector().cbb_mouse_mode->setCurrentIndex(getRendererThread().getRenderer().getMouseMode());
        getUiInspector().sbx_sensitivity->setValue(getRendererThread().getRenderer().getSensitivity());

        getUiInspector().sbx_timesteps->setValue(getSimulationThread().getSimulator().getTimestepsPerSecond());
        getUiInspector().sbx_frame_rate->setValue(getRendererThread().getRenderer().getFrameRate());
        getUiInspector().sbx_camera_frame_rate->setValue(getRendererThread().getRenderer().getCameraFrameRate());
        getUiInspector().sbx_gravity->setValue(getSimulationThread().getSimulator().getGravity());
        getUiInspector().sld_simulation_speed->setValue(getSimulationThread().getSimulationSpeed());

        getUiInspector().cbx_render->setChecked(getRendererThread().getRenderer().isRenderable());
        getUiInspector().cbx_show_axis->setChecked(getRendererThread().getRenderer().isShowAxis());
        getUiInspector().cbx_show_center_of_mass->setChecked(getRendererThread().getRenderer().isShowCenterOfMass());
        getUiInspector().cbx_show_connection_points->setChecked(getRendererThread().getRenderer().isShowConnectionPoints());
        getUiInspector().cbx_show_bounding_spheres->setChecked(getRendererThread().getRenderer().isShowBoundingSpheres());
        getUiInspector().cbx_follow_creature->setChecked(getRendererThread().getRenderer().isFollowCreature());
        getUiInspector().cbx_solid_draw->setChecked(getRendererThread().getRenderer().isSolidDraw());
        getUiInspector().cbx_black_and_white->setChecked(getRendererThread().getRenderer().isBlackAndWhite());
        getUiInspector().cbx_render_ground->setChecked(getRendererThread().getRenderer().isRenderGround());

    }

    void MainWindow::setupUi() {
        getUiMainWindow().setupUi(this);
        getUiInspector().setupUi(&getInspector());
        setSimulationMode(SM_FREE);
        addDockWidget(Qt::LeftDockWidgetArea, &getInspector());

        getUiInspector().inspector_tabs->setCurrentIndex(0);
        getInspector().setFloating(true);
        getInspector().adjustSize();

        QRect rect = Math::centerInDesktop(getInspector().geometry());
        rect.moveLeft(0);
        getInspector().setGeometry(rect);

        setCentralWidget(&getRendererThread().getRenderer());
        setGeometry(Math::centerInDesktop(geometry()));

        QObject::connect(getUiMainWindow().action_inspector, SIGNAL(triggered()),
                &getInspector(), SLOT(show()), Qt::DirectConnection);
        QObject::connect(getUiInspector().inspector_tabs, SIGNAL(currentChanged(int)),
                this, SLOT(changedCurrentTab(int)), Qt::DirectConnection);

        updateControls();
        setupControl();
        setupEvolution();
        setupBodyParts();

        getRendererThread().start();
    }

    void MainWindow::closeEvent(QCloseEvent* event) {
        (void) event;
        getRendererThread().stop();
        getSimulationThread().stop();
    }

    void MainWindow::setupControl() {
        //Mouse
        QObject::connect(getUiInspector().cbb_mouse_mode, SIGNAL(currentIndexChanged(int)),
                this, SLOT(changedMouseMode(int)));

        QObject::connect(getUiInspector().sbx_sensitivity, SIGNAL(valueChanged(double)),
                this, SLOT(changedSensitivity(double)));

        //Properties
        QObject::connect(getUiInspector().sbx_timesteps, SIGNAL(valueChanged(int)),
                this, SLOT(changedTimesteps(int)));

        QObject::connect(getUiInspector().sbx_frame_rate, SIGNAL(valueChanged(int)),
                this, SLOT(changedFrameRate(int)));

        QObject::connect(getUiInspector().sbx_camera_frame_rate, SIGNAL(valueChanged(int)),
                this, SLOT(changedCameraFrameRate(int)));

        QObject::connect(getUiInspector().cbb_simulation_mode, SIGNAL(currentIndexChanged(int)),
                this, SLOT(changedSimulationMode(int)));

        QObject::connect(getUiInspector().sbx_gravity, SIGNAL(valueChanged(double)),
                this, SLOT(changedGravity(double)));

        QObject::connect(getUiInspector().sbx_iterations, SIGNAL(valueChanged(int)),
                this, SLOT(changedIterations(int)));

        //Control
        QObject::connect(getUiInspector().btn_step, SIGNAL(clicked()),
                this, SLOT(clickStep()));

        QObject::connect(getUiInspector().btn_play_pause, SIGNAL(clicked()),
                this, SLOT(clickPlayPause()));

        QObject::connect(getUiInspector().sld_simulation_speed, SIGNAL(valueChanged(int)),
                this, SLOT(changedSimulationSpeed(int)));

        QObject::connect(getUiInspector().txt_shortcuts, SIGNAL(keyPressed(int)),
                this, SLOT(pressedShortcut(int)));

        QObject::connect(getUiInspector().btn_shortcuts, SIGNAL(toggled(bool)),
                this, SLOT(activateShortcuts(bool)));

        //Appearance
        QObject::connect(getUiInspector().cbx_render, SIGNAL(toggled(bool)),
                this, SLOT(changedRender(bool)));

        QObject::connect(getUiInspector().cbx_show_axis, SIGNAL(toggled(bool)),
                this, SLOT(changedShowAxis(bool)));

        QObject::connect(getUiInspector().cbx_show_center_of_mass, SIGNAL(toggled(bool)),
                this, SLOT(changedShowCenterOfMass(bool)));

        QObject::connect(getUiInspector().cbx_show_connection_points, SIGNAL(toggled(bool)),
                this, SLOT(changedShowConnectionPoints(bool)));

        QObject::connect(getUiInspector().cbx_show_bounding_spheres, SIGNAL(toggled(bool)),
                this, SLOT(changedShowBoundingSpheres(bool)));

        QObject::connect(getUiInspector().cbx_follow_creature, SIGNAL(toggled(bool)),
                this, SLOT(changedFollowCreature(bool)));

        QObject::connect(getUiInspector().cbx_solid_draw, SIGNAL(toggled(bool)),
                this, SLOT(changedSolidDraw(bool)));

        QObject::connect(getUiInspector().cbx_black_and_white, SIGNAL(toggled(bool)),
                this, SLOT(changedBlackAndWhite(bool)));

        QObject::connect(getUiInspector().cbx_render_ground, SIGNAL(toggled(bool)),
                this, SLOT(changedRenderGround(bool)));

    }

    void MainWindow::setupEvolution() {
        QObject::connect(getUiInspector().cbb_creature, SIGNAL(currentIndexChanged(int)),
                this, SLOT(changedCreature(int)));

        QObject::connect(getUiInspector().btn_create_creature, SIGNAL(clicked()),
                this, SLOT(clickCreateCreature()));

        QObject::connect(getUiInspector().btn_creature_add, SIGNAL(clicked()),
                this, SLOT(clickAddCreatureToWorld()));

        QObject::connect(getUiInspector().cbb_xml, SIGNAL(currentIndexChanged(int)),
                this, SLOT(changedXmlCreature(int)));

        QObject::connect(getUiInspector().btn_xml_from_clipboard, SIGNAL(clicked()),
                this, SLOT(clickXmlFromClipboard()));

        QObject::connect(getUiInspector().btn_xml_to_clipboard, SIGNAL(clicked()),
                this, SLOT(clickXmlToClipboard()));

        QObject::connect(getUiInspector().cbx_behavior_enable, SIGNAL(toggled(bool)),
                this, SLOT(changedBehaviorEnabled(bool)));

        QObject::connect(getUiInspector().cbx_behavior_on_ground, SIGNAL(toggled(bool)),
                this, SLOT(changedBehaviorOnGround(bool)));

        QObject::connect(getUiInspector().btn_set_evolution, SIGNAL(clicked()),
                this, SLOT(clickSetEvolution()));

        QObject::connect(getUiInspector().btn_reset_evolution, SIGNAL(clicked()),
                this, SLOT(clickResetEvolution()));

        //Experiments
        QObject::connect(getUiInspector().btn_add_experiment, SIGNAL(clicked()),
                this, SLOT(clickAddExperiment()));

        QObject::connect(getUiInspector().btn_remove_experiment, SIGNAL(clicked()),
                this, SLOT(clickRemoveExperiment()));

        QObject::connect(getUiInspector().btn_update_current_experiment, SIGNAL(clicked()),
                this, SLOT(clickUpdateCurrentExperiment()));

        QObject::connect(getUiInspector().btn_restart_experiments, SIGNAL(clicked()),
                this, SLOT(clickRestartExperiments()));

    }

    void MainWindow::setupBodyParts() {
        QObject::connect(getUiInspector().lst_body_parts, SIGNAL(itemSelectionChanged()),
                this, SLOT(changedBodyPartSelection()));

        QObject::connect(getUiInspector().btn_clear_forces, SIGNAL(clicked()),
                this, SLOT(clickClearForces()));

        QObject::connect(getUiInspector().btn_apply_central_force, SIGNAL(clicked()),
                this, SLOT(clickApplyCentralForce()));

        QObject::connect(getUiInspector().btn_apply_central_torque, SIGNAL(clicked()),
                this, SLOT(clickApplyCentralTorque()));

        QObject::connect(getUiInspector().btn_apply_impulse_force, SIGNAL(clicked()),
                this, SLOT(clickApplyImpulseForce()));

        QObject::connect(getUiInspector().btn_apply_impulse_torque, SIGNAL(clicked()),
                this, SLOT(clickApplyImpulseTorque()));
    }

    void MainWindow::setSimulationMode(eSimulationMode mode) {
        if (_simulation_thread) {
            pause();
            QObject::disconnect(&getSimulationThread(), SIGNAL(stopped()), this, SLOT(setPlayIcon()));
            QObject::disconnect(&getSimulationThread(), SIGNAL(started()), this, SLOT(setPauseIcon()));
            QObject::disconnect(&getSimulationThread(), SIGNAL(message(const QString&)), this, SLOT(sendUiMessage(const QString&)));
            delete _simulation_thread;
        }
        switch (mode) {
            case SM_FREE:
                setSimulationThread(*new FreeSimulationThread());
                getUiInspector().sbx_iterations->setValue(-1);
                break;
            case SM_EVOLUTION:
                setSimulationThread(*new EvolutiveSimulationThread());
                if (getUiInspector().sbx_iterations->value() <= 0) {
                    getUiInspector().sbx_iterations->setValue(100);
                }
                break;
            case SM_EXPERIMENTS:
                setSimulationThread(*new ExperimentDirectorThread(*_experiment_threads));
                getUiInspector().sbx_iterations->setValue(-1);
                break;
            case SM_INSTANT_REPLAY:
                int evaluation_time = getUiInspector().sbx_evaluation_time->value();
                setSimulationThread(*new InstantReplayThread(evaluation_time));
                getUiInspector().sbx_iterations->setValue(-1);
                getSimulationThread().setBehaviorEnabled(true);
                getSimulationThread().setBehaviorOnGround(true);
                break;
            default:
                BDEBUG(TO_STRING(mode));
                assert(0);
        }
        getUiInspector().sbx_iterations->setEnabled(mode == SM_EVOLUTION);
        getUiInspector().btn_set_evolution->setEnabled(mode == SM_EVOLUTION);
        QObject::connect(&getSimulationThread(), SIGNAL(stopped()),
                this, SLOT(setPlayIcon()));
        QObject::connect(&getSimulationThread(), SIGNAL(started()),
                this, SLOT(setPauseIcon()));
        QObject::connect(&getSimulationThread(), SIGNAL(message(const QString&)),
                this, SLOT(sendUiMessage(const QString&)));

    }

    //--------------------------------------------------------------------------
    //SLOTS
    //--------------------------------------------------------------------------
    //CONTROL

    void MainWindow::changedMouseMode(int index) {
        getRendererThread().getRenderer().setMouseMode((QGLRenderer::eMouseMode)index);
    }

    void MainWindow::changedSensitivity(double sensitivity) {
        getRendererThread().getRenderer().setSensitivity(sensitivity);
    }

    void MainWindow::changedTimesteps(int tps) {
        getSimulationThread().getSimulator().setTimestepsPerSecond(tps);
    }

    void MainWindow::changedFrameRate(int fps) {
        getRendererThread().getRenderer().setFrameRate(fps);
    }

    void MainWindow::changedCameraFrameRate(int fps) {
        getRendererThread().getRenderer().setCameraFrameRate(fps);
    }

    void MainWindow::changedSimulationMode(int index) {
        setSimulationMode((eSimulationMode) index);
    }

    void MainWindow::changedGravity(double gravity) {
        getSimulationThread().getSimulator().setGravity(gravity);
    }

    void MainWindow::changedIterations(int iterations) {
        getSimulationThread().setIterations(iterations);
    }

    void MainWindow::clickStep() {
        getSimulationThread().iterate();
    }

    void MainWindow::clickPlayPause() {
        bool play = !getSimulationThread().isRunning();
        if (play) {
            this->play();
        } else {
            this->pause();
        }
    }

    void MainWindow::changedSimulationSpeed(int speed) {
        getSimulationThread().setSimulationSpeed(speed);
    }

    void MainWindow::changedRender(bool value) {
        getRendererThread().getRenderer().setRenderable(value);
        getRendererThread().notify();
    }

    void MainWindow::changedShowAxis(bool value) {
        getRendererThread().getRenderer().setShowAxis(value);
    }

    void MainWindow::changedShowCenterOfMass(bool value) {
        getRendererThread().getRenderer().setShowCenterOfMass(value);
    }

    void MainWindow::changedShowConnectionPoints(bool value) {
        getRendererThread().getRenderer().setShowConnectionPoints(value);
    }

    void MainWindow::changedShowBoundingSpheres(bool value) {
        getRendererThread().getRenderer().setShowBoundingSpheres(value);
    }

    void MainWindow::changedFollowCreature(bool value) {
        getRendererThread().getRenderer().setFollowCreature(value);
    }

    void MainWindow::changedSolidDraw(bool value) {
        getRendererThread().getRenderer().setSolidDraw(value);
    }

    void MainWindow::changedBlackAndWhite(bool value) {
        getRendererThread().getRenderer().setBlackAndWhite(value);
    }

    void MainWindow::changedRenderGround(bool value) {
        getRendererThread().getRenderer().setRenderGround(value);
    }

    void MainWindow::changedCurrentTab(int tab) {
        getUiInspector().lbl_current_tab->setText(
                getUiInspector().inspector_tabs->tabToolTip(tab));
    }

    void MainWindow::changedCreature(int index) {
        Creature* tmp_creature = NULL;
        switch (index) {
            case 0: tmp_creature = NULL;
                break;
            case 1: tmp_creature = new BasicCreature(0, 0);
                break;
            case 2: tmp_creature = new QuadrupedCreature(0, 0);
                break;
            case 3: tmp_creature = new HumanCreature(0, 0);
                break;
            case 4: tmp_creature = new HalfHumanCreature(0, 0);
                break;
            default:
                BDEBUG(TO_STRING(index));
                assert(0);
        }

        getUiInspector().sbx_body_parts->setEnabled(index == 0);

        if (tmp_creature) {
            getUiInspector().sbx_body_parts->setValue(tmp_creature->getNumberOfBodyParts());
            delete tmp_creature;
        }
        if (index > 0) {
            getUiInspector().cbb_evolution->setCurrentIndex(0);
        }
        getUiInspector().cbb_evolution->setEnabled(index > 0);
    }

    void MainWindow::createCreature(Creature* creature) {
        removeCreature();
        setCreature(creature);
        if (creature) {
            loadCreatureDetails(*creature);
        }
    }

    void MainWindow::removeCreature() {
        if (getCreature()) {
            if (getCreature() == getSimulationThread().getSimulator().currentCreature()) {
                getSimulationThread().getSimulator().removeCreature();
            }
            getRendererThread().getRenderer().deselectBodyPart(NULL);
            delete getCreature();
            setCreature(NULL);
            getUiInspector().lst_body_parts->clear();
        }
    }

    void MainWindow::loadCreatureDetails(const Creature& creature) {
        getUiInspector().lst_body_parts->clear();
        for (int i = 0; i < creature.getNumberOfBodyParts(); ++i) {
            sendUiMessage(QString(creature.getBodyPart(i).getName().c_str()));
            getUiInspector().lst_body_parts->addItem(
                    QString(creature.getBodyPart(i).getName().c_str()));
        }
    }

    void MainWindow::clickCreateCreature() {
        int body_parts = getUiInspector().sbx_body_parts->value();
        int constraints = body_parts - 1;
        int hidden_layers = getUiInspector().sbx_hidden_layers->value();
        int neurons_per_layer = getUiInspector().sbx_neurons_per_layer->value();
        int index = getUiInspector().cbb_creature->currentIndex();
        Creature* creature = NULL;
        switch (index) {
            case 0: creature = new Creature(body_parts, constraints, hidden_layers, neurons_per_layer);
                break;
            case 1: creature = new BasicCreature(hidden_layers, neurons_per_layer);
                break;
            case 2: creature = new QuadrupedCreature(hidden_layers, neurons_per_layer);
                break;
            case 3: creature = new HumanCreature(hidden_layers, neurons_per_layer);
                break;
            case 4: creature = new HalfHumanCreature(hidden_layers, neurons_per_layer);
                break;
            default: BDEBUG(TO_STRING(index));
                assert(0);
        }
        if (index > 0) {
            creature->set();
        }
        createCreature(creature);
        getUiInspector().btn_creature_add->setEnabled(index > 0);
    }

    void MainWindow::clickAddCreatureToWorld() {
        getSimulationThread().getSimulator().removeCreature();
        getSimulationThread().getSimulator().reset();
        getSimulationThread().getSimulator().addCreature(*getCreature());
    }

    void MainWindow::changedBehaviorEnabled(bool value) {
        getSimulationThread().setBehaviorEnabled(value);
    }

    void MainWindow::changedBehaviorOnGround(bool value) {
        getSimulationThread().setBehaviorOnGround(value);
    }

    void MainWindow::changedXmlCreature(int index) {
        getUiInspector().btn_xml_from_clipboard->setEnabled(index == 0);
    }

    void MainWindow::clickXmlFromClipboard() {
        QClipboard& clipboard = *QApplication::clipboard();
        std::string xml = "<Creatures>" +
                clipboard.text(QClipboard::Clipboard).toStdString() +
                "</Creatures>";
        QDomDocument doc;
        QString * error_msg = new QString();
        int* error_line = new int();
        int* error_col = new int();
        bool ok = doc.setContent(QString(xml.c_str()), error_msg, error_line, error_col);
        if (!ok) {
            std::string m = "Error loading creatures: " + error_msg->toStdString() +
                    " at [" + TO_STRING(*error_line) + " , " +
                    TO_STRING(*error_col) + "]";
            sendUiMessage(QString(m.c_str()));
        } else {
            sendUiMessage("XML from creatures is OK");
        }
        delete error_msg;
        delete error_line;
        delete error_col;
        if (!ok) {
            return;
        }
        InstantReplayThread* ir = dynamic_cast<InstantReplayThread*> (&getSimulationThread());
        if (!ir) {
            sendUiMessage("Simulation Mode inadequate. Use InstantReplay");
            return;
        }
        ir->removeAllCreatures();
        QDomNode root = doc.firstChild();
        QDomNode child = root.firstChild();
        bool* _ok = new bool;
        int index = 0;
        Creature* creature = NULL;
        while (!child.isNull()) {
            QDomElement e = child.toElement();
            *_ok = true;
            if (e.tagName() == "Creature") {
                creature = Creature::fromXml(e, _ok);
            }
            if (!*_ok) {
                sendUiMessage(("Problem loading creature " + TO_STRING(index)).c_str());
            } else {
                ir->addCreature(*creature);
            }
            child = child.nextSibling();
            ++index;
        }
        sendUiMessage(("Creatures added: " + TO_STRING(index)).c_str());
    }

    void MainWindow::clickXmlToClipboard() {
        QClipboard& clipboard = *QApplication::clipboard();
        int index = getUiInspector().cbb_xml->currentIndex();
        bool serialized = false;
        switch (index) {
            case 0:
                serialized = getCreature();
                if (serialized) {
                    clipboard.setText(QString(getCreature()->toXml().c_str()), QClipboard::Clipboard);
                }
                break;
            case 1:
                getSimulationThread().getSimulator().getLock().lockForRead();
                Creature* creature = getSimulationThread().getSimulator().currentCreature();
                if (creature) {
                    clipboard.setText(QString(creature->toXml().c_str()), QClipboard::Clipboard);
                }
                getSimulationThread().getSimulator().getLock().unlock();
                serialized = creature;
                break;
            case 2: break;
            default: BDEBUG(TO_STRING(index));
                assert(0);
        }
        if (serialized) {
            sendUiMessage("XML: The creature was successfully serialized to clipboard");
        } else {
            sendUiMessage("XML: The creature was NOT serialized to clipboard");
        }
    }

    void MainWindow::clickResetEvolution() {
        pause();
        setSimulationMode(SM_EVOLUTION);
    }

    void MainWindow::clickSetEvolution() {
        clickResetEvolution();
        getSimulationThread().setIterations(getUiInspector().sbx_iterations->value());
        getSimulationThread().setBehaviorEnabled(getUiInspector().cbx_behavior_enable->isChecked());
        getSimulationThread().setBehaviorOnGround(getUiInspector().cbx_behavior_on_ground->isChecked());
        int population_size = getUiInspector().sbx_swarm_size->value();
        int evaluation_time = getUiInspector().sbx_evaluation_time->value();
        int index = getUiInspector().cbb_evolution->currentIndex();
        switch (index) {
            case 0: //Behavior
            {
                if (!getCreature()) {
                    sendUiMessage("You must create a Creature first");
                    return;
                }
                EvolutionOfBehavior* evolution = new EvolutionOfBehavior(population_size, *getCreature());
                evolution->setEvaluationTime(evaluation_time);
                evolution->getModel().setSharingMethod(new RingSharingMethod());
                evolution->getModel().setVelocityClampingMethod(new BasicVelocityClamping());
                evolution->getModel().setInertiaUpdateMethod(NULL);
                EvolutiveSimulationThread* thread = dynamic_cast<EvolutiveSimulationThread*> (&getSimulationThread());
                if (thread) {
                    thread->setEvolution(evolution);
                } else {
                    sendUiMessage("Simulation Thread NOT appropiate for Evolution");
                }
            }
                break;
            case 1: //Morphology
                sendUiMessage("Not Implemented... No plans for implementation... Looks nice, though :P");
                break;
            case 2: //Morphology and Behavior
            {
                int body_parts = getUiInspector().sbx_body_parts->value();
                int hidden_layers = getUiInspector().sbx_hidden_layers->value();
                int neurons_per_layer = getUiInspector().sbx_neurons_per_layer->value();
                double min_size = getUiInspector().sbx_min_size->value();
                double max_size = getUiInspector().sbx_max_size->value();
                double min_mass = getUiInspector().sbx_min_mass->value();
                double max_mass = getUiInspector().sbx_max_mass->value();
                int topology = 0;
                EvolutionOfMorphologyAndBehavior* evolution = new EvolutionOfMorphologyAndBehavior(
                        population_size, body_parts, hidden_layers, neurons_per_layer,
                        getSimulationThread().getIterations(),
                        min_size, max_size, min_mass, max_mass);
                evolution->setEvaluationTime(evaluation_time);
                if (topology == 0) {
                    evolution->getPsoModel().setSharingMethod(new RingSharingMethod(2));
                } else {
                    evolution->getPsoModel().setSharingMethod(new StarSharingMethod());
                }
                EvolutiveSimulationThread* thread = dynamic_cast<EvolutiveSimulationThread*> (&getSimulationThread());
                if (thread) {
                    thread->setEvolution(evolution);
                } else {
                    sendUiMessage("Simulation Thread NOT appropiate for Evolution");
                }
            }
                break;
            default:
                BDEBUG(TO_STRING(index));
                assert(0);
        }
    }

    void MainWindow::play() {
        getSimulationThread().play();
    }

    void MainWindow::pause() {
        getSimulationThread().stop();
    }

    void MainWindow::setPlayIcon() {
        QIcon icon;
        icon.addPixmap(QPixmap(QString::fromUtf8(":/icon/res/icons/player_play.png")),
                QIcon::Normal, QIcon::On);
        getUiInspector().btn_play_pause->setIcon(icon);
    }

    void MainWindow::setPauseIcon() {
        QIcon icon;
        icon.addPixmap(QPixmap(QString::fromUtf8(":/icon/res/icons/player_pause.png")),
                QIcon::Normal, QIcon::On);
        getUiInspector().btn_play_pause->setIcon(icon);
    }

    void MainWindow::sendUiMessage(const QString& message) {
        QString html_message;
        html_message += "<p style=\"background-color: ";
        html_message += (_toggle_color_message ? "#e6f0fe" : "#ffffff");
        html_message += ";margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; text-indent:0px;";
        html_message += "\">";
        html_message += "*";
        html_message += Qt::escape(message);
        html_message += "</p>";
        _toggle_color_message = !_toggle_color_message;
        QTextCursor cursor(getUiInspector().html_messages->textCursor());
        bool is_at_end = cursor.atEnd();

        getUiInspector().html_messages->append(html_message);

        if (is_at_end) {
            cursor.movePosition(QTextCursor::End);
            getUiInspector().html_messages->ensureCursorVisible();
        }
        getUiInspector().html_messages->setTextCursor(cursor);
    }

    void MainWindow::changedBodyPartSelection() {
        double mass = 0.0;
        double size_x = 0.0, size_y = 0.0, size_z = 0.0;
        getUiInspector().lst_body_part_details->clear();
        getUiInspector().led_body_part_mass->clear();
        getUiInspector().led_body_part_size->clear();
        Creature* creature = getCreature();
        if (!creature) {
            return;
        }
        for (int i = 0; i < getUiInspector().lst_body_parts->count(); ++i) {
            if (getUiInspector().lst_body_parts->item(i)->isSelected()) {
                getRendererThread().getRenderer().selectBodyPart(creature->getBodyPart(i).getRigidBody());
                showBodyDetails(*creature, creature->getBodyPart(i));
                mass += creature->getBodyPart(i).getMass();
                size_x += creature->getBodyPart(i).getSizeX();
                size_y += creature->getBodyPart(i).getSizeY();
                size_z += creature->getBodyPart(i).getSizeZ();
            } else {
                getRendererThread().getRenderer().deselectBodyPart(
                        creature->getBodyPart(i).getRigidBody());
            }
        }
        getUiInspector().led_body_part_mass->setText(QString(TO_STRING(mass).c_str()));
        getUiInspector().led_body_part_size->setText(
                QString(("[" + TO_STRING(size_x) + " ; " +
                TO_STRING(size_y) + " ; " + TO_STRING(size_z) + "]").c_str()));
    }

    void MainWindow::showBodyDetails(const Creature& creature, const BodyPart& body_part) {
        getUiInspector().lst_body_part_details->addItem(QString(
                body_part.getName().c_str()));
        getUiInspector().lst_body_part_details->addItem(QString(
                ("  Mass: " + TO_STRING(body_part.getMass())).c_str()));
        getUiInspector().lst_body_part_details->addItem(QString(
                ("  Torque: " + TO_STRING(body_part.getMaxTorque())).c_str()));
        getUiInspector().lst_body_part_details->addItem(QString(
                std::string("  Size").c_str()));
        getUiInspector().lst_body_part_details->addItem(QString(
                ("  [x]: " + TO_STRING(body_part.getSizeX())).c_str()));
        getUiInspector().lst_body_part_details->addItem(QString(
                ("  [y]: " + TO_STRING(body_part.getSizeY())).c_str()));
        getUiInspector().lst_body_part_details->addItem(QString(
                ("  [z]: " + TO_STRING(body_part.getSizeZ())).c_str()));
        //Angles

        BodyPart* parent = body_part.getParentId() == Creature::B_NONE
                ? NULL : &creature.getBodyPart(body_part.getParentId());
        if (parent) {
            getUiInspector().lst_body_part_details->addItem(QString(
                    ("  Parent: " + parent->getName()).c_str()));
            //            getUiInspector().lst_body_part_details->addItem(QString(std::string("  Angles:").c_str()));
            //            getUiInspector().lst_body_part_details->addItem(QString(
            //                    ("   XY:" + TO_STRING(
            //                    MathUtil::getAngle(MathUtil::XY,
            //                    parent->getRigidBody()->getCenterOfMassPosition(),
            //                    body.getRigidBody()->getCenterOfMassPosition()))).c_str()));
            //            getUiInspector().lst_body_part_details->addItem(QString(
            //                    ("   YZ:" + TO_STRING(
            //                    MathUtil::getAngle(MathUtil::YZ,
            //                    parent->getRigidBody()->getCenterOfMassPosition(),
            //                    body.getRigidBody()->getCenterOfMassPosition()))).c_str()));
            //            getUiInspector().lst_body_part_details->addItem(QString(
            //                    ("   ZX:" + TO_STRING(
            //                    MathUtil::getAngle(MathUtil::ZX,
            //                    parent->getRigidBody()->getCenterOfMassPosition(),
            //                    body.getRigidBody()->getCenterOfMassPosition()))).c_str()));
        }
    }

    void MainWindow::clickClearForces() {
        getUiInspector().sbx_force_x->setValue(0.0);
        getUiInspector().sbx_force_y->setValue(0.0);
        getUiInspector().sbx_force_z->setValue(0.0);
        clickApplyForce(FT_NONE);
    }

    void MainWindow::clickApplyForce(eForceType type) {
        Creature* creature = getCreature();
        if (!creature) {
            return;
        }
        if (type == FT_NONE) {
            for (int i = 0; i < creature->getNumberOfBodyParts(); ++i) {
                creature->getBodyPart(i).getRigidBody()->clearForces();
            }
        } else {
            std::vector<btRigidBody*>& bodies = getRendererThread().getRenderer().getSelectedBodyParts();
            btVector3 forces(getUiInspector().sbx_force_x->value(),
                    getUiInspector().sbx_force_y->value(),
                    getUiInspector().sbx_force_z->value());

            for (std::vector<btRigidBody*>::iterator it = bodies.begin();
                    it != bodies.end(); ++it) {
                btRigidBody* rigid_body = *it;
                rigid_body->activate(true);
                switch (type) {
                    case FT_CENTRAL_FORCE: rigid_body->applyCentralForce(forces);
                        break;
                    case FT_CENTRAL_TORQUE: rigid_body->applyTorque(forces);
                        break;
                    case FT_IMPULSE_FORCE: rigid_body->applyCentralImpulse(forces);
                        break;
                    case FT_IMPULSE_TORQUE: rigid_body->applyTorqueImpulse(forces);
                        break;
                    default:
                        BDEBUG(TO_STRING(type));
                        assert(0);
                }
            }
        }
    }

    void MainWindow::clickApplyCentralForce() {
        clickApplyForce(FT_CENTRAL_FORCE);
    }

    void MainWindow::clickApplyCentralTorque() {
        clickApplyForce(FT_CENTRAL_TORQUE);
    }

    void MainWindow::clickApplyImpulseForce() {
        clickApplyForce(FT_IMPULSE_FORCE);
    }

    void MainWindow::clickApplyImpulseTorque() {
        clickApplyForce(FT_IMPULSE_TORQUE);
    }

    void MainWindow::clickAddExperiment() {
        int swarm_size = getUiInspector().sbx_exp_swarm_size->value();
        int body_parts = getUiInspector().sbx_exp_body_parts->value();
        int hidden_layers = getUiInspector().sbx_exp_hidden_layers->value();
        int neurons_per_layer = getUiInspector().sbx_exp_neurons_per_layer->value();
        int iterations = getUiInspector().sbx_exp_iterations->value();
        int repetitions = getUiInspector().sbx_exp_repetitions->value();
        double min_mass = getUiInspector().sbx_exp_min_mass->value();
        double max_mass = getUiInspector().sbx_exp_max_mass->value();
        double min_size = getUiInspector().sbx_exp_min_size->value();
        double max_size = getUiInspector().sbx_exp_max_size->value();
        int max_iterations = getUiInspector().sbx_iterations->value();
        int evaluation_time = getUiInspector().sbx_evaluation_time->value();
        bool behavior_enabled = getUiInspector().cbx_behavior_enable->isChecked();
        bool behavior_on_ground = getUiInspector().cbx_behavior_on_ground->isChecked();
        int pso_topology = getUiInspector().cbb_pso_topology->currentIndex();

        std::string base_codename;
        base_codename += "p" + TO_STRING(swarm_size) + "-bp" + TO_STRING(body_parts) +
                "-hl" + TO_STRING(hidden_layers) + "-nl" + TO_STRING(neurons_per_layer) +
                +"-it" + TO_STRING(iterations);
        if (pso_topology == 0) {
            base_codename += "-ring2";
        } else {
            base_codename += "-star";
        }
        EvolutionOfMorphologyAndBehavior* evolution = NULL;
        ExperimentThread* experiment_thread = NULL;
        for (int i = 0; i < repetitions; ++i) {
            evolution = new EvolutionOfMorphologyAndBehavior(swarm_size, body_parts,
                    hidden_layers, neurons_per_layer, max_iterations, min_size, max_size, min_mass, max_mass);
            BDEBUG("min-size = " + TO_STRING(min_size));
            BDEBUG("max-size = " + TO_STRING(max_size));
            BDEBUG("min-mass = " + TO_STRING(min_mass));
            BDEBUG("max-mass = " + TO_STRING(max_mass));
            evolution->setEvaluationTime(evaluation_time);
            if (pso_topology == 0) {
                evolution->getPsoModel().setSharingMethod(new RingSharingMethod(2));
                BDEBUG("Using RingSharing(2)")
            } else {
                evolution->getPsoModel().setSharingMethod(new StarSharingMethod());
                BDEBUG("Using StarSharing");
            }
            experiment_thread = new ExperimentThread(*evolution);
            experiment_thread->setIterations(iterations);
            experiment_thread->setBehaviorEnabled(behavior_enabled);
            experiment_thread->setBehaviorOnGround(behavior_on_ground);
            experiment_thread->setExperiment(*new Experiment(base_codename, iterations, swarm_size, body_parts));
            _experiment_threads->push_back(experiment_thread);
            getUiInspector().lst_experiments->addItem(QString(base_codename.c_str()));
        }
    }

    void MainWindow::clickRemoveExperiment() {
        std::vector<QListWidgetItem*> remove;

        for (int i = 0; i < getUiInspector().lst_experiments->count(); ++i) {
            if (getUiInspector().lst_experiments->item(i)->isSelected()) {
                remove.push_back(getUiInspector().lst_experiments->item(i));
                ExperimentThread* to_remove = _experiment_threads->at(i);
                _experiment_threads->erase(_experiment_threads->begin() + i);
                sendUiMessage(QString(("Deleted experiment: " + to_remove->getExperiment()._description).c_str()));
                delete to_remove;
            }
        }
        for (int i = 0; i < remove.size(); ++i) {
            getUiInspector().lst_experiments->removeItemWidget(remove[i]);
            delete remove[i];
        }
    }

    void MainWindow::clickUpdateCurrentExperiment() {
        ExperimentDirectorThread* thread = dynamic_cast<ExperimentDirectorThread*> (&getSimulationThread());
        std::string message;
        if (thread) {
            ExperimentThread* experiment = thread->getCurrentExperiment();
            if (experiment) {
                message = experiment->getExperiment()._description;
            } else {
                message = "No experiments pending.";
            }
        } else {
            message = "Not in Experiments Mode";
        }
        getUiInspector().led_current_experiment->setText(QString(message.c_str()));
    }

    void MainWindow::clickRestartExperiments() {
        ExperimentDirectorThread* thread = dynamic_cast<ExperimentDirectorThread*> (&getSimulationThread());
        std::string message;
        if (thread) {
            thread->setNextExperiment(0);
            message = "Updated";
        } else {
            message = "Not in Experiments Mode";
        }
        getUiInspector().led_current_experiment->setText(QString(message.c_str()));
    }

    void MainWindow::activateShortcuts(bool active) {
        this->_activate_shortcuts = active;

        if (active) {
            getUiInspector().txt_shortcuts->grabKeyboard();
            getUiInspector().txt_shortcuts->setFocus();
        } else {
            getUiInspector().txt_shortcuts->releaseKeyboard();
        }
    }

    void MainWindow::pressedShortcut(int key) {
        if (!_activate_shortcuts) {
            return;
        }
        QGLRenderer& renderer = getRendererThread().getRenderer();
        switch (key) {
            case 'm': case 'M':
                sendUiMessage("Esto es un mensaje de prueba");
                break;
            case 'r': case 'R':
                renderer._camera_eye[0] = QGLRenderer::DEFAULT_CAMERA_X;
                renderer._camera_eye[1] = QGLRenderer::DEFAULT_CAMERA_Y;
                renderer._camera_eye[2] = QGLRenderer::DEFAULT_CAMERA_Z;
                renderer._camera_aim[0] = 0.0;
                renderer._camera_aim[1] = 0.0;

                renderer._camera_eye_lock[0] = 0.0;
                renderer._camera_eye_lock[1] = 0.0;
                renderer._camera_eye_lock[2] = 0.0;
                break;
            case 'l': case 'L':
                renderer.lockCamera();
                BDEBUG("locked camera at ( " + TO_STRING(renderer._camera_eye_lock[0]) + " ; " +
                        TO_STRING(renderer._camera_eye_lock[1]) + " ; " +
                        TO_STRING(renderer._camera_eye_lock[2]) + " )");
                break;
            case 'i': case 'I':
            {
                BDEBUG("camera[pos(" + TO_STRING(renderer._camera_eye[0]) + " ; "
                        + TO_STRING(renderer._camera_eye[1]) + " ; "
                        + TO_STRING(renderer._camera_eye[2]) + "), "
                        + "aim(" + TO_STRING(renderer._camera_aim[0]) + " ; "
                        + TO_STRING(renderer._camera_aim[1]) + ")]");
                getSimulationThread().getSimulator().getLock().lockForRead();
                Creature* creature = getSimulationThread().getSimulator().currentCreature();
                if (creature) {
                    for (std::vector<btRigidBody*>::const_iterator it = renderer.getSelectedBodyParts().begin();
                            it != renderer.getSelectedBodyParts().end(); ++it) {
                        const btRigidBody* body = *it;
                        const btVector3& com = body->getCenterOfMassPosition();
                        btTransform transform;
                        transform.setIdentity();
                        Constraint::locateConnectionOrigin(
                                creature->getBodyPart(creature->getIndex(body)), Constraint::BOX_TOP, transform);
                        transform = body->getCenterOfMassTransform() * transform;

                        btVector3 conn(transform.getOrigin().getX(), transform.getOrigin().getY(), transform.getOrigin().getZ());

                        transform.setIdentity();
                        body->getMotionState()->getWorldTransform(transform);
                        BDEBUG("rad: " + TO_STRING(transform.getRotation().getAngle()) +
                                " W: " + TO_STRING(transform.getRotation().getW()) +
                                " X: " + TO_STRING(transform.getRotation().getX()) +
                                " Y: " + TO_STRING(transform.getRotation().getY()) +
                                " Z: " + TO_STRING(transform.getRotation().getZ()));
                        BDEBUG("deg: " + TO_STRING(Math::radToDeg(transform.getRotation().getAngle())) +
                                " W: " + TO_STRING(Math::radToDeg(transform.getRotation().getW())) +
                                " X: " + TO_STRING(Math::radToDeg(transform.getRotation().getX())) +
                                " Y: " + TO_STRING(Math::radToDeg(transform.getRotation().getY())) +
                                " Z: " + TO_STRING(Math::radToDeg(transform.getRotation().getZ())));
                        BDEBUG("--------------------");

                    }
                }
                getSimulationThread().getSimulator().getLock().unlock();
            }
                break;
            case 'p': case 'P':
                clickPlayPause();
                break;
            case ' ':
                BDEBUG("reset");
                getSimulationThread().getSimulator().reset();
                break;
            case '1':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_BOX);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '2':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CAPSULE_X);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '3':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CAPSULE_Y);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '4':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CAPSULE_Z);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '5':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CONE_X);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '6':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CONE_Y);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '7':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CONE_Z);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '8':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CYLINDER_X);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '9':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CYLINDER_Y);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '0':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_CYLINDER_Z);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '!':
            {
                Creature* creature = new PrimitiveCreature(BodyPart::S_SPHERE);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '@':
            {
                Creature* creature = new BasicCreature();
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '#':
            {
                Creature* creature = new QuadrupedCreature();
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case '$':
            {
                MatchCreature* creature = new MatchCreature();
                btTransform t;
                //                t.setIdentity();
                //                t.getOrigin().setZ(100);
                //                t.getOrigin().setY(100);
                //                t.getOrigin().setX(50);
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case 'h':case 'H':
            {
                Creature* creature = new HumanCreature();
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case 'j':case 'J':
            {
                Creature* creature = new HalfHumanCreature();
                creature->set();
                createCreature(creature);
                clickAddCreatureToWorld();
            }
                break;
            case ';':
            {
                getSimulationThread().getSimulator().getLock().lockForWrite();
                Creature * creature = getSimulationThread().getSimulator().currentCreature();
                if (!creature) {
                    sendUiMessage("Hook NOT set. There is no creature in world.");
                } else {
                    //                    const btVector3 btPivotA(0, 0.0, 0.0f); // right next to the door slightly outside
                    btVector3 axis(0.0f, 1.0f, 0.0f); // pointing upwards, aka Y-axis
                    //                    btPoint2PointConstraint* constraint = new btPoint2PointConstraint(
                    //                            *creature->getBodyPart(0).getRigidBody(), btVector3(0.0, 0.0, 0.0));
                    btHingeConstraint* constraint = new btHingeConstraint(*creature->getRoot().getRigidBody(),
                            btVector3(0.0, 0.0, 0.0), axis);
                    constraint->setLimit(0.0, 0.0);
                    setHook(constraint);
                    getSimulationThread().getSimulator().getWorld().addConstraint(constraint, true);
                    sendUiMessage("Hook is ON");
                }
                getSimulationThread().getSimulator().getLock().unlock();
            }
                break;
            case ',':
            {
                if (!getHook()) {
                    sendUiMessage("Hook NOT set.");
                    break;
                }
                getSimulationThread().getSimulator().getLock().lockForWrite();
                getSimulationThread().getSimulator().getWorld().removeConstraint(getHook());
                delete getHook();
                sendUiMessage("Hook is OFF");
                getSimulationThread().getSimulator().getLock().unlock();
            }
                break;
            case 'g': case 'G':
            {
                btVector3 g = getSimulationThread().getSimulator().getWorld().getGravity();
                if (g.y() != double(0.0)) {
                    getUiInspector().sbx_gravity->setValue(0.0);
                } else {
                    getUiInspector().sbx_gravity->setValue(-9.80665);
                }
                break;
            }
            case 'f': case 'F':
                getUiInspector().cbx_follow_creature->setChecked(!renderer.isFollowCreature());
                BDEBUG("Camera is " + (renderer.isFollowCreature() ? "" : " NOT ") + "following the creature");
                break;
            case 'a': case 'A': case Qt::Key_Left :
                        renderer.moveCamera(QGLRenderer::CM_SLIDE, 2.0 * renderer.getSensitivity());
                break;
            case 'd': case 'D': case Qt::Key_Right :
                        renderer.moveCamera(QGLRenderer::CM_SLIDE, -2.0 * renderer.getSensitivity());
                break;
            case 'w': case 'W':case Qt::Key_Up :
                        renderer.moveCamera(QGLRenderer::CM_ADVANCE, -2.0 * renderer.getSensitivity());
                break;
            case 's': case 'S':case Qt::Key_Down :
                        renderer.moveCamera(QGLRenderer::CM_ADVANCE, 2.0 * renderer.getSensitivity());
                break;
            case Qt::Key_Backspace :
                        renderer.moveCamera(QGLRenderer::CM_AIM_HORIZONTAL, -180.0);
                break;
            case Qt::Key_Delete :
                        renderer.moveCamera(QGLRenderer::CM_AIM_HORIZONTAL, -90.0);
                break;
            case '`':
                getUiInspector().cbb_mouse_mode->setCurrentIndex(
                        (renderer.getMouseMode() + 1) % QGLRenderer::MM_MODE_COUNT);
                break;
            case Qt::Key_Tab :
                        getUiInspector().lst_body_parts->clearSelection();
                if (_body_part_selection_index < getUiInspector().lst_body_parts->count()) {
                    getUiInspector().lst_body_parts->item(_body_part_selection_index)->setSelected(true);
                    ++_body_part_selection_index;
                } else {
                    _body_part_selection_index = 0;
                }
                break;
            case Qt::Key_Backtab :
                if (_body_part_selection_index >= getUiInspector().lst_body_parts->count()) {
                    _body_part_selection_index = 0;
                }
                getUiInspector().lst_body_parts->item(_body_part_selection_index)->setSelected(true);
                ++_body_part_selection_index;
                break;
            case 'c': case 'C':
                getUiInspector().cbx_show_center_of_mass->setChecked(!renderer.isShowCenterOfMass());
                BDEBUG((renderer.isShowCenterOfMass() ? "" : "NOT ") + "Showing Center of Mass");
                break;
            case 'b': case 'B':
                getUiInspector().cbx_show_bounding_spheres->setChecked(!renderer.isShowBoundingSpheres());
                BDEBUG((renderer.isShowBoundingSpheres() ? "" : "NOT ") + "Showing Bounding Spheres");
                break;
            case '.':
                getUiInspector().cbx_show_connection_points->setChecked(!renderer.isShowConnectionPoints());
                BDEBUG((renderer.isShowConnectionPoints() ? "" : "NOT ") + "Showing Connection Points");
                break;
            case Qt::Key_Return : getSimulationThread().iterate();
                BDEBUG("Simulation stepped");
                break;
            case 't':case 'T':
            {
                getSimulationThread().getSimulator().getLock().lockForRead();
                Creature* creature = getSimulationThread().getSimulator().currentCreature();
                if (creature) {
                    creature->calculateMaxTorque();
                }
                getSimulationThread().getSimulator().getLock().unlock();
            }
                break;
            default:
                BDEBUG("Key undefined: (" + TO_STRING(key) + "):" + (char) key);
        }
    }

    int MainWindow::main(int argc, char** argv) {
        QApplication app(argc, argv);
        MainWindow window;
        window.setupUi();
        window.show();
        return app.exec();
    }

}
